package org.example.server.rest;

import org.example.java.model.Constant;
import org.example.server.model.core.Movie;
import org.example.server.model.core.Rating;
import org.example.server.model.core.Tag;
import org.example.server.model.core.User;
import org.example.server.model.recom.Recommendation;
import org.example.server.model.request.*;
import org.example.server.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

//用于处理电影相关的功能
@Controller
@RequestMapping("/rest/movies")
public class MovieRestApi {

    @Autowired
    private RecommenderService recommenderService;

    @Autowired
    private UserService userService;

    @Autowired
    private MovieService movieService;

    @Autowired
    private TagService tagService;

    @Autowired
    private RatingService ratingService;

    private Logger logger = LoggerFactory.getLogger(MovieRestApi.class);

    //    ******首页******

    /**
     * 提供获取实时推荐信息的接口【混合推荐】 需要考虑冷启动问题
     * url:  /rest/movies/stream?username=abc&num=100
     *
     * @param username
     * @param model
     * @return {success: true, movies:[]}
     */
    @RequestMapping(path = "/stream", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getRealtimeRecommendations(@RequestParam("username") String username, @RequestParam("num") int num, Model model) {
        User user = userService.findUserByUsername(username);
        List<Recommendation> recommendations = recommenderService.getStreamRecsMovies(new GetStreamRecsRequest(user.getUid(), num));
        if (recommendations.size() == 0) {
            Random random = new Random();
            recommendations = recommenderService.getGenresTopMovies(new GetGenresTopMoviesRequest(user.getGenres().get(random.nextInt(user.getGenres().size())), num));
        }
        List<Integer> ids = new ArrayList<>();
        for (Recommendation recom : recommendations) {
            ids.add(recom.getMid());
        }
        List<Movie> result = movieService.getMoviesByMids(ids);
        model.addAttribute("success", true);
        model.addAttribute("movies", result);
        return model;
    }

    /**
     * 提供获取离线推荐信息的接口
     * url:  /rest/movies/offline?username=abc&num=100
     *
     * @param username
     * @param model
     * @return
     */
    @RequestMapping(path = "/offline", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getOfflineRecommendations(@RequestParam("username") String username, @RequestParam("num") int num, Model model) {
        User user = userService.findUserByUsername(username);
        List<Recommendation> recommendations = recommenderService.getUserCFMovies(new GetUserCFRequest(user.getUid(), num));
        if (recommendations.size() == 0) {
            Random random = new Random();
            recommendations = recommenderService.getGenresTopMovies(new GetGenresTopMoviesRequest(user.getGenres().get(random.nextInt(user.getGenres().size())), num));
        }
        List<Integer> ids = new ArrayList<>();
        for (Recommendation recom : recommendations) {
            ids.add(recom.getMid());
        }
        List<Movie> result = movieService.getMoviesByMids(ids);
        model.addAttribute("success", true);
        model.addAttribute("movies", result);
        return model;
    }

    /**
     * 提供获取热门推荐信息的接口
     * url:  /rest/movies/hot?num=100
     *
     * @param num
     * @param model
     * @return
     */
    @RequestMapping(path = "/hot", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getHotRecommendations(@RequestParam("num") int num, Model model) {
        model.addAttribute("success", true);
        model.addAttribute("movies", recommenderService.getHotRecommendations(new GetHotRecommendationRequest(num)));
        return null;
    }

    /**
     * 提供获取历史热门电影信息的接口
     * url:  /rest/movies/rate?num=100
     *
     * @param num
     * @param model
     * @return
     */
    @RequestMapping(path = "/rate", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getRateMoreRecommendation(@RequestParam("num") int num, Model model) {
        model.addAttribute("success", true);
        model.addAttribute("movies", recommenderService.getRateMoreMovies(new GetRateMoreMoviesRequest(num)));
        return model;
    }

    /**
     * 获取最新电影信息的接口
     * url:  /rest/movies/new?num=100
     *
     * @param num
     * @param model
     * @return
     */
    @RequestMapping(path = "/new", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getNewRecommendations(@RequestParam("num") int num, Model model) {
        model.addAttribute("success", true);
        model.addAttribute("movies", recommenderService.getNewMovies(new GetNewMoviesRequest(num)));
        return model;
    }

    /**
     * 获取高分排行电影信息的接口
     * url:  /rest/movies/score?num=100
     *
     * @param num
     * @param model
     * @return
     */
    @RequestMapping(path = "/score", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getScoreRecommendations(@RequestParam("num") int num, Model model) {
        model.addAttribute("success", true);
        //GetNewMoviesRequest其实都是只有个num，沿用也可
        model.addAttribute("movies", recommenderService.getScoreMovies(new GetNewMoviesRequest(num)));
        return model;
    }

    //    ******模糊检索******

    /**
     * 提供基于名称/描述的模糊检索功能
     * url:  /rest/movies/query?query=abc&num=100
     *
     * @param query
     * @param num
     * @param model
     * @return
     */
    @RequestMapping(value = "/query", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getFuzzySearchMovies(@RequestParam("query") String query, @RequestParam("num") int num, Model model) {
        model.addAttribute("success", true);
        model.addAttribute("movies", recommenderService.getFuzzyMovies(new GetFuzzySearchMoviesRequest(query, num)));
        return model;
    }

    //    ******详细页面******

    /**
     * 获取单个电影的信息
     * url:  /rest/movies/info/123
     *
     * @param mid
     * @param model
     * @return
     */
    @RequestMapping(value = "/info/{mid}", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model gFetMovieInfo(@PathVariable("mid") int mid, Model model) {
        model.addAttribute("success", true);
        model.addAttribute("movie", movieService.findMovieInfo(mid));
        return model;
    }

    //


    /**
     * 提供给电影打标签的功能
     * url:  /rest/movies/addtag/123?username=abc&tagname=abc
     *
     * @param mid
     * @param username
     * @param tagname
     * @param model
     */
    @RequestMapping(value = "/addtag/{mid}", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public void addTagToMovie(@PathVariable("mid") int mid, @RequestParam("username") String username, @RequestParam("tagname") String tagname, Model model) {
        User user = userService.findUserByUsername(username);

        Tag tag = new Tag(user.getUid(), mid, tagname, System.currentTimeMillis() / 1000);
        tagService.addTagToMovie(tag);
    }

    /**
     * 获取电影的所有标签
     * url:  /rest/movies/tag/123
     *
     * @param mid
     * @param model
     * @return
     */
    @RequestMapping(value = "/tag/{mid}", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getMovieTags(@PathVariable("mid") int mid, Model model) {
        model.addAttribute("success", true);
        model.addAttribute("tag", tagService.getMovieTags(mid));
        return model;
    }

    /**
     * 获取电影相似的电影推荐（启动es才能用）
     * url:  /rest/movies/same/123?num=100
     *
     * @param mid
     * @param num
     * @param model
     * @return
     */
    @RequestMapping(value = "/same/{mid}", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getSimMoviesRecommendation(@PathVariable("mid") int mid, @RequestParam("num") int num, Model model) {
        model.addAttribute("success", true);
        model.addAttribute("movies", recommenderService.getHybridRecommendations(new GetHybridRecommendationRequest(0.5, mid, num)));
        return model;
    }

    //

    /**
     * 提供给电影打分的功能（要启动redis）
     * url:  /rest/movies/rate/123?username=abc&score=3.5
     *
     * @param username
     * @param mid
     * @param score
     * @param model
     * @return
     */
    @RequestMapping(value = "/rate/{mid}", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public void retaMovie(@RequestParam("username") String username, @PathVariable("mid") int mid, @RequestParam("score") double score, Model model) {
        User user = userService.findUserByUsername(username);

        Rating rating = new Rating(user.getUid(), mid, score, System.currentTimeMillis() / 1000);
        ratingService.rateToMovie(rating);
        //输出埋点日志
        logger.info(Constant.USER_RATING_LOG_PREFIX + rating.getUid() + "|" + rating.getMid() + "|" + rating.getScore() + "|" + rating.getTimestamp());
    }

    //    ******影片类别******

    /**
     * 提供影片类别的查找
     * url:  /rest/movies/genres?genres=abc&num=10
     *
     * @param genres
     * @param num
     * @param model
     * @return
     */
    @RequestMapping(value = "/genres", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getGenresMovies(@RequestParam("genres") String genres, @RequestParam("num") int num, Model model) {
        model.addAttribute("success", true);
        model.addAttribute("genres", recommenderService.getGenresMovies(new GetGenresMoviesRequest(genres, num)));
        return model;
    }

    //    ******用户页面******

    /**
     * 提供用户的所有电影评分记录
     * url:  /rest/movies/ratings?username=123@qq.com
     *
     * @param username
     * @param model
     * @return
     */
    @RequestMapping(value = "/ratings", produces = "application/json", method = RequestMethod.GET)
    @ResponseBody
    public Model getUserRatings(@RequestParam("username") String username, Model model) {
        User user = userService.findUserByUsername(username);

        model.addAttribute("success", true);
        model.addAttribute("ratings", ratingService.getUserRatings(user.getUid()));
        return model;
    }

    //    提供获取图表数据
    public Model getUserChart(String username, Model model) {
        return null;
    }


}
